Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add kyve support #235

Merged
merged 82 commits into from
May 1, 2024
Merged

Add kyve support #235

merged 82 commits into from
May 1, 2024

Conversation

bz888
Copy link
Contributor

@bz888 bz888 commented Mar 4, 2024

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist

  • I have tested locally
  • I have performed a self review of my changes
  • Updated any relevant documentation
  • Linked to any relevant issues
  • I have added tests relevant to my changes
  • Any dependent changes have been merged and published in downstream modules
  • My code is up to date with the base branch
  • I have updated relevant changelogs. We suggest using chan

Copy link

github-actions bot commented Mar 4, 2024

Coverage report

St.
Category Percentage Covered / Total
🔴 Statements 46.81% 2451/5236
🟡 Branches 76.28% 238/312
🔴 Functions 45.87% 100/218
🔴 Lines 46.81% 2451/5236

Test suite run success

58 tests passing in 7 suites.

Report generated by 🧪jest coverage report action from e138dc5

packages/node/src/utils/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve.spec.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve.spec.ts Outdated Show resolved Hide resolved
packages/node/src/indexer/api.service.ts Outdated Show resolved Hide resolved
packages/node/src/utils/bundle.json Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Show resolved Hide resolved
packages/node/src/indexer/api.service.ts Outdated Show resolved Hide resolved
@bz888 bz888 marked this pull request as ready for review April 2, 2024 15:30
packages/node/src/configure/NodeConfig.ts Outdated Show resolved Hide resolved
packages/node/src/configure/NodeConfig.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyveTypes.ts Show resolved Hide resolved
packages/node/src/utils/kyve/storageRetriever.ts Outdated Show resolved Hide resolved
packages/node/src/indexer/api.service.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@stwiname stwiname left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work when workers are enabled? It doesn't seem to make sense that each worker download the same bundles

packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyveConnection.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/yargs.ts Outdated Show resolved Hide resolved
packages/node/src/yargs.ts Outdated Show resolved Hide resolved
packages/node/src/configure/NodeConfig.ts Show resolved Hide resolved
Copy link
Contributor

@stwiname stwiname left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When testing this it never seems to use Kyve, only RPC

packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyveConnection.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyveConnection.ts Outdated Show resolved Hide resolved
packages/node/src/indexer/api.service.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/utils/cosmos.ts Outdated Show resolved Hide resolved
packages/node/src/indexer/api.service.ts Outdated Show resolved Hide resolved
packages/node/src/configure/NodeConfig.ts Outdated Show resolved Hide resolved
packages/node/src/indexer/api.service.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
bundleId =
Math.max(...nearestBundle.map((b) => parseDecimal(b.id))) + 1;

this.cachedBundleDetails[bundleId] = this.getBundleById(bundleId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment is redundant

packages/node/src/utils/kyve/kyve.ts Outdated Show resolved Hide resolved
Comment on lines 260 to 268
await Promise.race([
new Promise((resolve, reject) => {
writeStream.on('open', resolve);
writeStream.on('error', reject);
}),
delay(5).then(() => {
throw new Error('Timeout: File stream did not open');
}),
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a timeout function, but to me there is a bigger issue that this promise doesn't resolve. It should always resolve

limit: '1',
},
})
).pagination.total,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a little fragile, why not set reverse on the pagination and get the most recent?

We can also cache the finalized bundle

Comment on lines 219 to 227
bundleId =
Math.max(...nearestBundle.map((b) => parseDecimal(b.id))) + 1;

bundle = await this.getBundleById(bundleId);

while (parseDecimal(bundle.to_key) < height) {
bundleId++;
bundle = await this.getBundleById(bundleId);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be a separate function. We can make it easy to switch between iterating and binary search if the functions have the same interface

}
}

await fs.promises.chmod(bundleFilePath, 0o666); // Reset permissions if polling exceeds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? What if the bundle is just taking a really long time to download?

Comment on lines 262 to 263
// XXXX:SCOTT This can get stuck and not resolve, it seems a file can get stuck with permissions not reset (indexer restart)
// Its probably worth adding a timeout on this function
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can have a better comment explaining the timeout

.pipe(writeStream)
.on('error', reject)
.on('finish', async () => {
await fs.promises.chmod(bundleFilePath, 0o444);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not move this out of the promise?

await this.downloadAndProcessBundle(bundle);
return await this.readFromFile(bundleFilePath);
} catch (e: any) {
if (['EEXIST', 'EACCES'].includes(e.code)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth tying this array with the other occurrence?

Comment on lines 328 to 333
for (const file of files) {
if (this.isBundleFile(file)) {
const id = parseDecimal(file.match(BUNDLE_FILE_ID_REG(this.poolId))[1]);
bundles.push(await this.getBundleById(id));
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be a map/promise.all instead

Comment on lines 347 to 348
const currentBundle = await this.getBundleFromCache(height);
if (!currentBundle) return [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be removed

Comment on lines 356 to 358
const isOutsiderBuffer =
height < parseDecimal(b.from_key) - bufferSize ||
height > parseDecimal(b.to_key) + bufferSize;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think only bundles below the buffer matter, If we're doing a binary search or have any future bundles they will be removed from the cache

const blocks = await this.updateCurrentBundleAndDetails(height);
const blockData = this.findBlockByHeight(height, blocks);
assert(blockData, `Unable to retrieve block: ${height} from file cache.`);
// XXXX:SCOTT blockData is regularly undefined, this should not happen and is not handled.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed

@stwiname
Copy link
Contributor

stwiname commented Apr 23, 2024

With some testing:

  • Kyve is still not enabled by default
  • Getting some other errors Failed to fetch blocks: [16605] via Kyve, switching to rpc SyntaxError: Unterminated string in JSON at position 3768953
  • With more recent blocks (Archway > 4,284,742) there is a large number of warnings that only happens when Kyve is enabled e.g. Unable to find message for event. tx=04EA876F2EA5FE15B4E6B140726F03B24D8F6CF3E452FCA94124E7809BF46430 messageIdx=1
  • AxiosError: Request failed with status code 500 i don't know if this is because of Kyve rpc or fetching bundles
  • Removing bundle seems to happen multiple times, i noticed this at startup
024-04-23T23:12:14.440Z <kyve> DEBUG Removing bundle 70
2024-04-23T23:12:14.440Z <kyve> DEBUG Removing bundle 70
2024-04-23T23:12:14.440Z <kyve> DEBUG Removing bundle 70
2024-04-23T23:12:14.440Z <kyve> DEBUG Removing bundle 70
2024-04-23T23:12:14.442Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.442Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.442Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.442Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.442Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.442Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.443Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.444Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.444Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.444Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.444Z <kyve> DEBUG Removing bundle 88
2024-04-23T23:12:14.444Z <kyve> DEBUG Removing bundle 88


const poolId = await KyveApi.fetchPoolId(chainId, lcdClient);

logger.info(`Kyve API connected`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be handy to have logging when Kyve isn't being used too

Copy link
Contributor

@stwiname stwiname left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried the latest and kept getting this error:

2024-04-25T23:11:33.863Z <worker #0> ERROR Uncaught Exception Error: ENOENT: no such file or directory, stat 'bundle_2_100.json'
/Users/scotttwiname/Projects/subql/node_modules/@subql/node-core/dist/indexer/worker/worker.js:130
    throw e;
    ^

[Error: ENOENT: no such file or directory, stat 'bundle_2_100.json'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'stat',
  path: 'bundle_2_100.json'
}
Thrown at:


Node.js v20.11.1
(node:74466) WARNING: Exited the environment with code 7
    at processPromiseRejections (node:internal/process/promises:289:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:32)

const isStale = async (file: string) =>
((await fs.promises.stat(file)).mode & 0o777).toString(8) === '200';

files
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a promise.all?

Comment on lines 189 to 209
private async bundleIdIterator(height: number): Promise<number> {
let bundle: BundleDetails;
let bundleId: number;

const cachedBundles = await this.getResolvedBundleDetails();
const nearestBundle = cachedBundles.filter(
(b) => parseDecimal(b.to_key) < height,
);

bundleId = Math.max(...nearestBundle.map((b) => parseDecimal(b.id))) + 1;

bundle = await this.getBundleById(bundleId);

while (parseDecimal(bundle.to_key) < height) {
bundleId++;
bundle = await this.getBundleById(bundleId);
}
return parseDecimal(bundle.id);
}

private async getBundleId(height: number): Promise<number> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These names can be more similar, also having a JSDOC description how they differ would be handy

let bundleId: number;

const cachedBundles = await this.getResolvedBundleDetails();
const nearestBundle = cachedBundles.filter(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be undefined, please add a test

await this.downloadAndProcessBundle(bundle);
return await this.readFromFile(bundleFilePath);
} catch (e: any) {
if (['EEXIST', 'EACCES', 'ENOENT'].includes(e.code)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the ENOENT case happen?

Copy link

gitguardian bot commented Apr 26, 2024

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
Once a secret has been leaked into a git repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@stwiname stwiname merged commit fcefdcd into main May 1, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants